﻿/*
 * PsCaster.cpp
 *
 *  Created on: 2016年8月24日
 *      Author: zhengboyuan
 */

#include "BasicType.h"
#include "PsCaster.h"
#include "PsApplication.h"
#include "UdpPsMediaCaster.h"
#include "URtpPsMediaCaster.h"
#include "CRtpPsMediaCaster.h"
#include "CRtpEsMediaCaster.h"

#include "CLog.h"
#include "MFormatUtil.h"
#include "AppConst.h"
#include "CTcpMediaCaster.h"
#include "RtpConst.h"


static PsApplication& app()
{
	return PsApplication::instance();
}




/**
 * 初始化
 * @return 0 表示成功
 */
DLLEXPORT int pscaster_init()
{
	app().init();

	return 0;
}

/**
 * 反初始化
 * @return
 */
DLLEXPORT int pscaster_quit()
{
	app().quit();

	return 0;
}


/**
 * 打开发送通道
 * @param handle	句柄
 * @param protocol	传输协议, 暂支持UDP
 * @param outPort	本地端口
 * @param fmt		媒体格式
 * @return 0 表示成功
 */
DLLEXPORT int pscaster_open(pscaster_t* handle, int protocol, int outPort, const MFormat* fmt)
{
	return pscaster_openEx(handle, protocol, outPort, fmt, NULL);
}


DLLEXPORT int pscaster_openEx(pscaster_t* handle, int protocol, int outPort, const MFormat* fmt, const PsCasterParams* params)
{
	CLog::info("pscaster_openEx protocol:%d, port:%d\n", protocol, outPort);

	CLog::info("pscaster_openEx fmt video. codec:%d, clockRate:%d\n", fmt->codec, fmt->clockRate);
	CLog::info("pscaster_openEx fmt audio. codec:%d, channels:%d, freq:%d, rate:%d\n",
		fmt->audioCodec, fmt->channels, fmt->sampleRate, fmt->audioRate);

	if (params)
	{
		CLog::info("payload: %d, ssrc:%d\n", params->payload, params->ssrc);
	}

	if (!handle)
	{
		return EINVAL;
	}

	PsMediaCasterPtr caster;
	if (protocol == PSCASTER_PROTOCOL_UDP)
	{
		CLog::info("new av::UdpPsMediaCaster\n");
		caster.reset(new av::UdpPsMediaCaster());
	}
	else if (protocol == PSCASTER_PROTOCOL_TCP)
	{
		return EINVAL;
	}
	else if (protocol == PSCASTER_PROTOCOL_RTP || protocol == PSCASTER_PROTOCOL_RTP_TCP)
	{
		av::RtpPsMediaCaster* rtpCaster;
		
		if (params && (params->es > 0))
		{
			CLog::info("new av::CRtpEsMediaCaster\n");
			rtpCaster = new av::CRtpEsMediaCaster(protocol);
		}
		else
		{
			CLog::info("new av::CRtpPsMediaCaster\n");
			rtpCaster = new av::CRtpPsMediaCaster(protocol);
		}

		rtpCaster->setPayload(params->payload);
		rtpCaster->setSsrc(params->ssrc);

		caster.reset(rtpCaster);
	}
	else
	{
		CLog::info("new av::UdpPsMediaCaster\n");

		caster.reset(new av::UdpPsMediaCaster());
	}

	av::MediaFormat mfmt;
	av::MFormatUtil::copyTo(fmt, mfmt);

	int ret = caster->open("", outPort, mfmt);
	if (ret != 0)
	{
		return ret;
	}

	*handle = app().put(caster);

	caster->setID(*handle);

	return 0;
}


/**
 * 关闭通道
 * @param handle 通道句柄
 */
DLLEXPORT void pscaster_close(pscaster_t handle)
{
	PsMediaCasterPtr caster = app().remove(handle);
	if (caster)
	{
		caster->close();
	}
}


/**
 * 添加发送目标
 * @param handle 通道句柄
 * @param ip		地址
 * @param port		端口
 * @return	0 表示成功
 */
DLLEXPORT int pscaster_add_target(pscaster_t handle, const char* ip, int port)
{
	CLog::info("pscaster_add_target. ip:%s, port:%d\n", ip, port);

	if ((ip == NULL) || (strlen(ip) == 0))
	{
		return EINVAL;
	}

	PsMediaCasterPtr caster = app().get(handle);
	if (!caster)
	{
		return ENOENT;
	}

	bool done = caster->addTarget(ip, port);

	return done ? 0 : EACCES;
}

/**
 * 删除发送目标
 * @param handle	通道
 * @param ip		地址
 * @param port	端口
 * @return 0 表示成功
 */
DLLEXPORT int pscaster_remove_target(pscaster_t handle, const char* ip, int port)
{
	CLog::info("pscaster_remove_target. ip:%s, port:%d\n", ip, port);

	if ((ip == NULL) || (strlen(ip) == 0))
	{
		return EINVAL;
	}

	PsMediaCasterPtr caster = app().get(handle);
	if (!caster)
	{
		return ENOENT;
	}

	caster->removeTarget(ip, port);

	return 0;
}


/**
 * 删除所有的发送目标
 * @param handle
 * @return
 */
DLLEXPORT int pscaster_remove_all_target(pscaster_t handle)
{
	CLog::info("pscaster_remove_all_target. \n");

	PsMediaCasterPtr caster = app().get(handle);
	if (!caster)
	{
		return ENOENT;
	}

	caster->removeAllTarget();
	return 0;
}


DLLEXPORT int pscaster_write(pscaster_t handle, const MPacket* packet)
{
	if (!packet || !packet->data)
	{
		CLog::warning("invalid packet. handle: %d\n", handle);
		return EINVAL;
	}
	
	PsMediaCasterPtr caster = app().get(handle);
	if (!caster)
	{
		CLog::warning("no such caster. handle: %d\n", handle);
		return ENOENT;
	}

	av::MediaPacketPtr pkt(new av::MediaPacket());
	
	pkt->write(packet->data, packet->size);

	pkt->type = (packet->type == MTYPE_VIDEO ? MTYPE_VIDEO : MTYPE_AUDIO);

	pkt->pts = packet->pts;
	pkt->duration = packet->duration;
	pkt->flags = packet->flags;

	//CLog::info("pscaster_write type:%d, size:%d, flags:%d, pts:%lld\n", pkt->type, pkt->size, pkt->flags, pkt->pts);

	caster->write(pkt);

	return 0;
}


/**
 * 设置缓冲区最大时长, 单位为毫秒
 * @param ms
 */
DLLEXPORT void pscaster_setQueueDuration(int ms)
{
	// pass
}

/**
 * 设置socket发送缓冲区大小
 * @param size
 */
DLLEXPORT void pscaster_setSendBufSize(int size)
{
	if (size > 0)
	{
		AppConst::SEND_BUFFER_SIZE = size;
	}
}

DLLEXPORT int pscaster_setEventCallback(pscaster_t handle, PsCasterEventCallback cb, void* context)
{
    PsMediaCasterPtr caster = app().get(handle);
    if (!caster)
    {
        CLog::warning("no such caster. handle: %d\n", handle);
        return ENOENT;
    }

    caster->setEventCallback(cb, context);
    return 0;
}

DLLEXPORT int pscaster_isValid(pscaster_t handle)
{
    PsMediaCasterPtr caster = app().get(handle);
    return (caster.get() != NULL);
}


DLLEXPORT void pscaster_enableReconnect(int enabled)
{
    av::CTcpMediaCaster::RECONNECT_ENABLED = (enabled > 0);
}

DLLEXPORT void pscaster_setTcpPrefixSize(int size)
{
    if (size == av::CTcpMediaCaster::kShort)
    {
        av::CTcpMediaCaster::PREFIX_MODE = av::CTcpMediaCaster::kShort;
    }
    else
    {
        av::CTcpMediaCaster::PREFIX_MODE = av::CTcpMediaCaster::kDword;
    }
}

DLLEXPORT void pscaster_setRtpMaxSize(int size)
{
    if (size < av::RtpConst::RTP_MIN_SIZE)
    { 
        return;
    }
    
    av::RtpConst::RTP_PACKET_SIZE = size;
}